/*
 *
 *  *    Copyright 2020-2021 Luter.me
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *      http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.luter.heimdall.core.token.store;



import com.luter.heimdall.core.config.HeimdallProperties;
import com.luter.heimdall.core.context.WebContextHolder;
import com.luter.heimdall.core.listener.TokenEventListener;
import com.luter.heimdall.core.token.PageModel;
import com.luter.heimdall.core.token.SimpleToken;
import com.luter.heimdall.core.token.TokenHelper;

import java.util.Collection;

/**
 * Token 存储
 * <p>
 * 1、 缓存 颁发的 token，实现类似 Session+Cookie 的会话功能。
 * <p>
 * 2、可作为 jwt 模式下的白名单缓存，将颁发的 jwt token 进行缓存
 * <p>
 * 注意:
 * <p>
 * 1、 Cookie 功能、获取客户端 IP 功能，只在配置了WebContextHolder后才会生效;
 * <p>
 * 2、Cookie 功能在:(Cookie.enabled = true && jwt.enabledWhiteList = false) 的情况下生效;
 *
 * @author luter
 * @see HeimdallProperties#getToken()
 * @see TokenHelper#addCookie(WebContextHolder, HeimdallProperties, SimpleToken)
 * @see TokenHelper#setRia(WebContextHolder, SimpleToken)
 */
public interface TokenStore {

    /**
     * 是否支持到期自动清理
     * <p>
     * 比如 redis 的 ttl 机制
     * <p>
     * 这个方法用作定时清理任务判断是否需要执行，
     * 对于不具备自动到期删除的缓存，定时任务会定期清理数据。
     *
     * @return the cache type enum
     */
    boolean isSelfExpired();

    /**
     * 存储 Token
     *
     * @param token the token
     * @return the simple token
     */
    SimpleToken saveToken(SimpleToken token);

    /**
     * 根据 ID 获取存储的 Token
     *
     * @param tokenId the token id
     * @return the token
     */
    SimpleToken getToken(String tokenId);

    /**
     * 更新 存储的 Token 信息
     *
     * @param token the token
     * @return the simple token
     */
    SimpleToken update(SimpleToken token);

    /**
     * 根据principal获取这个principal所有存储的 Token
     *
     * @param principal the principal
     * @return the principal tokens
     */
    Collection<SimpleToken> getPrincipalTokens(String principal);

    /**
     * 获取当前所有存储的 Token
     * <p>
     * 注意:数据量大的情况下，这是一个耗费资源的操作。会一次性加载所有数据到内存
     *
     * @return the active tokens
     */
    Collection<SimpleToken> getActiveTokens();

    /**
     * 分页方式获取当前所有存储的 Token
     * <p>
     * 注意:数据量大的情况下，这是一个耗费资源的操作。
     * <p>
     * 首先会加载全部活动 token 到内存，然后开始分页
     *
     * @param pageNumber 页码
     * @param pageSize   每页数量
     * @return the active tokens page
     */
    default PageModel<SimpleToken> getActiveTokensPage(int pageNumber, int pageSize) {
        throw new UnsupportedOperationException("Unsupported operation");
    }

    /**
     * 根据 AppId 获取所有存储的 Token
     * <p>
     * 注意:数据量大的情况下，这是一个耗费资源的操作。
     * 会一次性加载所有数据到内存
     *
     * @param appId the app id
     * @return the active tokens
     */
    Collection<SimpleToken> getActiveTokens(String appId);

    /**
     * 分页方式根据 AppId 获取所有存储的 Token
     * <p>
     * 注意:数据量大的情况下，这是一个耗费资源的操作。
     * <p>
     * 首先会加载全部活动 token 到内存，然后开始分页
     *
     * @param appId      APP ID
     * @param pageNumber 页码
     * @param pageSize   每页数量
     * @return the active tokens page
     */
    default PageModel<SimpleToken> getActiveTokensPage(String appId, int pageNumber, int pageSize) {
        throw new UnsupportedOperationException("Unsupported operation");
    }

    /**
     * 从存储中踢出 Token，意味着注销登录状态
     *
     * @param tokenId the token id
     * @return the simple token
     */
    SimpleToken deleteToken(String tokenId);

    /**
     * 根据 principal 从存储中踢出所有 token
     *
     * @param principal the principal
     * @return the int
     */
    int deletePrincipalTokens(String principal);

    /**
     * 将某个 应用下的所有Token都踢出
     * <p>
     * 注意：这是一个大操作，这个应用下所有用户将需要重新登录
     *
     * @param appId App ID
     * @return the int
     */
    int deleteAppTokens(String appId);

    /**
     * 清理存储中的过期 token
     *
     * @return 清理过期 token 的总数
     */
    int clearExpiredTokens();

    /**
     * 获取当前存储的所哟 token 的总数
     *
     * @return the active tokens count
     */
    long getActiveTokensCount();

    /**
     * 获取当前所有 tokenStore 事件 监听器
     *
     * @return the listeners
     */
    Collection<TokenEventListener> getListeners();

}
